package com.cj.startup.manager

import android.content.Context
import android.os.Looper
import com.cj.startup.Startup
import com.cj.startup.StartupSortStore
import com.cj.startup.event.StartupObservable
import com.cj.startup.event.StartupObserve
import com.cj.startup.run.StartupRunnable
import com.cj.startup.sort.TopologySort
import java.util.concurrent.CountDownLatch

class StartupManager(
    private val context:Context,
    private val startupList:MutableList<Startup<*>>,
    private val awaitCountDownLatch: CountDownLatch,
) {

    companion object{
        /**
         * 手动加载
         */
        fun run(context: Context,startup: Startup<*>,finishedCallback:((Any?)->Unit) = {}){
            StartupObservable.addObserver(object :StartupObserve{
                override fun call(
                    event: StartupObserve.Event,
                    clazz: Class<out Startup<*>>?,
                    result: Any?
                ) {
                    if(event == StartupObserve.Event.FINISHED){
                        finishedCallback?.invoke(result)
                    }
                }
            }, mutableListOf(startup.javaClass))
            StartupManager(context, mutableListOf(),CountDownLatch(0)).run(startup)
        }

        /**
         * 自动加载
         */
        fun start(context: Context,startupList: MutableList<Startup<*>>):StartupManager{
            return StartupManager.Builder()
                .addAllStartup(startupList)
                .build(context)
        }

        /**
         * 添加观察任务执行情况
         */
        fun addObserver(observerObject:List<Class<out Startup<*>>>?,observe: StartupObserve){
            StartupObservable.addObserver(observe,observerObject)
        }

        /**
         * 移除观察者
         */
        fun removeObserver(observe: StartupObserve){
            StartupObservable.removeObserver(observe)
        }

        /**
         * 添加完成任务的回调
         * 只要任务完成就会回调
         */
        fun addFinishedObserver(observerObject:List<Class<out Startup<*>>>,observe: StartupObserve){
            val unfinishedObserverObject = mutableListOf<Class<out Startup<*>>>()
            observerObject.forEach { clazz ->
                val hasInitialized = StartupCacheManager.hasInitialized(clazz)
                if(hasInitialized){
                    observe.call(StartupObserve.Event.FINISHED,clazz,StartupCacheManager.obtainInitializedResult(clazz)?.result)
                }else{
                    unfinishedObserverObject.add(clazz)
                }
            }
            if(unfinishedObserverObject.isNotEmpty()){
                StartupObservable.addObserver(object :StartupObserve{
                    override fun call(
                        event: StartupObserve.Event,
                        clazz: Class<out Startup<*>>?,
                        result: Any?
                    ) {
                        if(event == StartupObserve.Event.FINISHED){
                            observe.call(StartupObserve.Event.FINISHED,clazz,result)
                        }
                    }
                },unfinishedObserverObject)
            }
        }
    }

    private var startupSortStore:StartupSortStore? = null

    private var isStarted = false

    /**
     * 自动初始化
     */
    fun start():StartupManager{
        if(isStarted){
            throw RuntimeException("Startup已经运行")
        }
        isStarted = true
        if(Looper.myLooper() != Looper.getMainLooper()){
            throw RuntimeException("Startup必须运行在主线程")
        }

        //将任务排序
        startupSortStore = TopologySort.sort(startupList)

        startupSortStore!!.result.forEach { startup ->
            executeStartup(startup)
        }
        return this
    }

    private fun executeStartup(startup: Startup<*>){
        checkExecuteStartup(startup.javaClass)
        val startupRunnable = StartupRunnable(context,startup,this)
        if(startup.callCreateOnMainThread()){
            startupRunnable.run()
        }else{
            startup.executor().execute(startupRunnable)
        }
    }

    /**
     * 手动初始化
     */
    fun run(startup: Startup<*>):StartupManager{
        if(isStarted){
            throw RuntimeException("Startup已经运行")
        }
        isStarted = true
        initializeComponent(startup)
        return this
    }

    /**
     * 手动初始化
     */
    private fun initializeComponent(startup: Startup<*>){
        startupSortStore = StartupSortStore.empty()
        innerInitializeComponent(startup)
    }

    private fun innerInitializeComponent(startup: Startup<*>){
        checkExecuteStartup(startup.javaClass)
        startupSortStore?.startupMap?.put(startup.javaClass,startup)
        startup.dependencies()?.forEach { parentClazz ->
            if(!StartupCacheManager.hasInitialize(parentClazz)){
                var startChildList = startupSortStore?.startupChildMap?.get(parentClazz)
                if(startChildList == null){
                    startChildList = mutableListOf()
                    startupSortStore?.startupChildMap?.set(parentClazz,startChildList)
                }
                startChildList.add(startup.javaClass)

                val instance = parentClazz.newInstance()
                innerInitializeComponent(instance)
            }
        }
        executeStartup(startup)
    }

    private fun checkExecuteStartup(clazz: Class<Startup<*>>){
        if(StartupCacheManager.hasInitialized(clazz)){
            throw java.lang.RuntimeException("该任务已经初始化：${clazz}")
        }
        if(StartupCacheManager.hasInitializing(clazz)){
            throw java.lang.RuntimeException("该任务已在初始化中：${clazz}")
        }
    }

    fun notifyChildren(startup: Startup<*>) {
        if(!startup.callCreateOnMainThread() && //完成的startup工作在子线程
            startup.waitOnMainThread()){ //并且需要主线程等待子线程执行完
            awaitCountDownLatch.countDown() //计数器-1
        }

        //获得已经完成的当前任务的所有子任务
        if(startupSortStore?.startupChildMap?.containsKey(startup.javaClass) == true){
            val childStartupClazzList = startupSortStore!!.startupChildMap[startup.javaClass]
            childStartupClazzList?.forEach { clazz ->
                //通知子任务Startup父任务已完成
                val childStartup = startupSortStore!!.startupMap[clazz]
                childStartup?.toNotify()
            }
        }
    }

    /**
     * 如果需要主线等待子线程执行完，调用此方法
     */
    fun await(){
        try{
            awaitCountDownLatch.await()
        }catch (e: InterruptedException){
            e.printStackTrace()
        }
    }

    //基于分阶段处理任务，不能用单例
    class Builder{
        private val startList:MutableList<Startup<*>> = mutableListOf()

        fun addStartup(startup: Startup<*>):Builder{
            this.startList.add(startup)
            return this
        }

        fun addAllStartup(startupList: MutableList<Startup<*>>):Builder{
            this.startList.addAll(startupList)
            return this
        }

        fun build(context: Context):StartupManager{
            var needAwaitCount = 0
            this.startList.forEach { startup ->
                //记录有多少个在子线程执行，又需要主线程等待的任务
                if(!startup.callCreateOnMainThread()
                    && startup.waitOnMainThread()){
                    needAwaitCount++
                }
            }
            //根据任务数新建一个锁,该锁主要用于主线程等待子线程(任务的waitOnMainThread() = true)执行完再执行
            val awaitCountDownLatch = CountDownLatch(needAwaitCount)
            return StartupManager(context,this.startList,awaitCountDownLatch)
        }
    }

}